package com.sofa.logging.listener;


import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.rolling.RollingFileAppender;
import ch.qos.logback.core.rolling.TimeBasedRollingPolicy;
import com.sofa.common.constants.MqConstants;
import com.sofa.logging.domain.po.OperationLogs;
import com.sofa.logging.service.IOperationLogsService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.nio.charset.StandardCharsets;
import java.time.Duration;


/**
* 消费消息   用于保存积分
* */
@Slf4j
@Component
@RequiredArgsConstructor
public class OperationLogsListener {

    private final IOperationLogsService operationLogsService;
    private static final Logger mqLogger = LoggerFactory.getLogger("operationFile");


    /**
     * 初始化输出日志,让日志消息的日志单独存放在一个文件中,不与其他日志信息混淆
     * 这一段让ai帮忙写的
     */
    @PostConstruct
    public void initLogger() {
        LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();

        PatternLayoutEncoder encoder = new PatternLayoutEncoder();
        encoder.setContext(context);
        encoder.setCharset(StandardCharsets.UTF_8);
        encoder.setPattern("%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n");
        encoder.start();

        RollingFileAppender<ILoggingEvent> fileAppender = new RollingFileAppender<>();
        fileAppender.setContext(context);
        fileAppender.setEncoder(encoder);
        fileAppender.setFile("logs/mq/operation-log.log");

        TimeBasedRollingPolicy<ILoggingEvent> rollingPolicy = new TimeBasedRollingPolicy<>();
        rollingPolicy.setContext(context);
        rollingPolicy.setParent(fileAppender);
        rollingPolicy.setFileNamePattern("logs/mq/operation-log.%d{yyyy-MM-dd}.log");
        rollingPolicy.setMaxHistory(7);
        rollingPolicy.start();

        fileAppender.setRollingPolicy(rollingPolicy);
        fileAppender.start();

        ch.qos.logback.classic.Logger logger = context.getLogger("operationFile");
        logger.setAdditive(false); // 不传给 root
        logger.setLevel(Level.INFO);
        logger.addAppender(fileAppender);
    }


    /**
    * 消费日志消息,并将其存入数据库
     * @param msg
    * */
//    @RabbitListener(bindings = @QueueBinding(
//            value = @Queue(name = MqConstants.Queue.SOFA_LOG_QUEUE, durable = "true"),
//            exchange = @Exchange(value = MqConstants.Exchange.SOFA_LOG_EXCHANGE, type = ExchangeTypes.TOPIC),
//            key = MqConstants.RoutingKey.SOFA_LOG_OPERATION
//    ))
    @RabbitListener(queues = MqConstants.Queue.SOFA_LOG_QUEUE)//修改成只负责监听,不干预任何声明逻辑,不然会由于死信队列导致参数不一致
    public void listenSignInListener(OperationLogs msg){
        //测试死信队列
//        log.info("测试死信队列");
//        throw new RuntimeException("测试死信队列");

        //TODO:后续有时间可以考虑用redis的String类型来防止消息的重复消费
/*        String redisKey = "log:consume:" + msg.getId();
        Boolean success = stringRedisTemplate.opsForValue().setIfAbsent(redisKey, "1", Duration.ofMinutes(5));
        if(!success){
            log.error("消息:{} 已经被消费", msg);
            return;
        }*/
        log.debug("消费到消息    {}", msg);
        // 1. 写入数据库
        operationLogsService.save(msg);
        // 2. 写入独立日志文件
        mqLogger.info("[操作日志] 日志ID={}, IP={}, 用户ID={}, 动作={}, 内容={}",
                msg.getId(),
                msg.getIp(),
                msg.getUserId(),
                msg.getAction(),
                msg.getDetail());
    }

}
